<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="root">
    <div class="c1">
      <div title="tt" id="id">hello1</div>
      <div title="tt2">hello2</div>
      <div title="tt3">hello3</div>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
    </div>
  </div>
  <script>
    // 虚拟dom
    // <div /> => {tag: 'div'}
    // 文本节点 => {tag:undefined, value: '文本节点'}
    // <div title="1" class="c"/> => {tag: 'div', data: {title: '1', class: 'c'}}
    // <div><p/></div> => {tag: 'div', children: [{tag:'p'}]}

    class VNode {
      constructor(tag, data, value, type, elm) {
        this.tag = tag && tag.toLowerCase();
        this.data = data;
        this.value = value;
        this.type = type;
        this.children = [];
      }

      appendChild(vnode) {
        this.children.push(vnode);
      }
    }

    /** 
     * 使用递归 来遍历 DOM 元素，生成 虚拟DOM
     * 
     * Vue 中的源码使用的栈结构，使用栈存储 父元素 来实现递归生成
     *  **/
    function getVNode(node) {
      let nodeType = node.nodeType;
      let _vnode = null;
      if(nodeType === 1) {
        let nodeName = node.nodeName;
        let attrs = node.attributes;
        let _attrObj = {};
        for(let i = 0;i < attrs.length; i ++) { // attrs[i] 属性节点（nodeType == 2）
          _attrObj[attrs[i].name] = attrs[i].nodeValue;
        }
        _vnode = new VNode(nodeName, _attrObj, undefined, nodeType);

        // 考虑 node 的子元素
        let childNodes = node.childNodes;
        for(let i = 0; i < childNodes.length; i++) {
          _vnode.appendChild(getVNode(childNodes[i])); //递归
        }
      } else if(nodeType === 3){
        _vnode = new VNode(undefined, undefined, node.nodeValue, nodeType);
      }

      return _vnode;
    }

    let root = document.querySelector('#root');

    let vroot = getVNode(root);

    // 将vNode转化成真正的DOM
    function parseVNode(vnode) {
      // 创建真实的DOM
      let type = vnode.type;
      let _node = null;
      if(type === 3) {
        return document.createTextNode(vnode.value); // 创建文本节点
      } else if( type === 1) {
        _node = document.createElement(vnode.tag);
        // 属性
        let data = vnode.data; //现在这个data是键值对
        Object.keys(data).forEach((key) => {
          let attrName = key;
          let attrValue = data[key];
          _node.setAttribute(attrName, attrValue);
        })

        // 子元素
        let children = vnode.children;
        children.forEach(subvnode => {
          _node.appendChild(parseVNode(subvnode)); // 递归转换子元素 ( 虚拟DOM )
        })

        return _node;
      }
    }

    // 在真正vue中也是使用 递归 + 栈 数据类型
    let dom2 = parseVNode(vroot);

    // 验证，只要将转换后的DOM打印出来，看看是不是一样的
    console.log(dom2);
</script>
</body>
</html>